<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .bigImg{width: 350px;height: 450px;position: relative;}
    .bigImg .m_box{width: 350px;height: 350px;position: relative;}
    .bigImg .m_box span{position: absolute;left:0;top:0;background: rgba(255,0,0,0.5);display: none;}
    .bigImg .m_box em{width: 100%;height:100%;position: absolute;left:0;top:0;z-index: 1;}
    .bigImg .l_box{position: absolute;width: 350px;height:350px;left: 380px;top:0;overflow: hidden;display: none;}
    .bigImg .l_box img{position: absolute;left:0;top:0;}
  </style>
</head>
<body>
  <div class="bigImg">
    <div class="m_box">
      <img src="./imgs/m0.jpg" alt="">
      <span></span>
      <em></em>
    </div>
    <div class="l_box">
      <img src="./imgs/l0.jpg" alt="">
    </div>
  </div>
</body>
<script>

  // 放大镜：等比例移动
  // 数据：各种元素，各种尺寸
  // 方法：绑定事件，显示相关元素（注意尺寸的获取），隐藏相关元素，在左侧移动，计算比例，计算右侧应移动的距离

  function bigImg(){
    this.mBox = $(".m_box");
    this.lBox = $(".l_box");
    this.mSpan = $(".m_box span");
    this.lImg = $(".l_box img");

    this.addEvent();
  }
  bigImg.prototype.addEvent = function(){
    const that = this;
    this.mBox.onmouseover = function(){
      // 显示
      that.show()
    }
    this.mBox.onmouseout = function(){
      // 隐藏
      that.hide()
    }
    this.mBox.onmousemove = function(eve){
      const e = eve || window.event;
      // 左侧遮罩层移动
      that.leftMove(e)
      // 计算比例
      that.xy()
      // 计算右侧图片要移动的距离
      that.rightMove()
    }
  }
  bigImg.prototype.show = function(){
    // 显示遮罩层和右侧容器
    this.mSpan.style.display = "block";
    this.lBox.style.display = "block";

    // 根据右侧大图显示的比例，计算左侧遮罩层的尺寸
    this.mSpan.style.width = this.lBox.offsetWidth / this.lImg.offsetWidth * this.mBox.offsetWidth + "px";
    this.mSpan.style.height = this.lBox.offsetHeight / this.lImg.offsetHeight * this.mBox.offsetHeight + "px";
  }
  bigImg.prototype.hide = function(){
    // 隐藏
    this.mSpan.style.display = "none";
    this.lBox.style.display = "none";
  }
  bigImg.prototype.leftMove = function(e){
    // 计算相对于左侧容器的坐标 - 遮罩层的一半（保证鼠标在遮罩层中间）
    this.l = e.offsetX - this.mSpan.offsetWidth/2;
    this.t = e.offsetY - this.mSpan.offsetHeight/2;
    // 提前计算遮罩层能移动的最大距离
    this.maxW = this.mBox.offsetWidth - this.mSpan.offsetWidth;
    this.maxH = this.mBox.offsetHeight - this.mSpan.offsetHeight;
    // 边界限定
    if(this.l < 0) this.l = 0;
    if(this.t < 0) this.t = 0;
    if(this.l > this.maxW) this.l = this.maxW;
    if(this.t > this.maxH) this.t = this.maxH;
    // 将计算好的距离设置给遮罩层
    this.mSpan.style.left = this.l + "px"
    this.mSpan.style.top = this.t + "px"
  }
  bigImg.prototype.xy = function(){
    this.x = this.l / this.maxW;
    this.y = this.t / this.maxH;
  }
  bigImg.prototype.rightMove = function(){
    // 根据遮罩层移动的比例，计算右侧大图要移动的距离（注意正反）
    this.lImg.style.left = -this.x * (this.lImg.offsetWidth - this.lBox.offsetWidth) + "px";
    this.lImg.style.top = -this.y * (this.lImg.offsetHeight - this.lBox.offsetHeight) + "px";
  }

  const b = new bigImg();
  console.log(b)

  // 选择器的封装（偷懒）
  function $(s){
    return document.querySelector(s);
  }
  
</script>
</html>